package org.feng.controller;

import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.util.concurrent.TimeUnit;

/**
 * redisson 锁控制器
 *
 * @author fengjinsong
 * @date 2023-06-29 10:48:14
 * @version: 1.0
 */
@Slf4j
@RestController
public class RedissonLockController {

    @Resource(name = "singleRedissonClient")
    private RedissonClient redissonClient;

    @Setter
    @Value("${spring.application.name}")
    private String applicationName;
    @Setter
    @Value("${server.port}")
    private Integer serverPort;

    private static final String LOCK_NAME = "order-number";

    @GetMapping("/lockInSingleJvm")
    public String lockInSingleJvm() {
        // 获取锁
        RLock lock = redissonClient.getLock(LOCK_NAME);
        log.info("[{}:{}]开始加锁", applicationName, serverPort);
        try {
            // 尝试获取锁（等待时间为0）
            boolean tryLock = lock.tryLock(0L, 10L, TimeUnit.SECONDS);

            log.info("[{}:{}]加锁是否成功：{}", applicationName, serverPort, tryLock);
            if (!tryLock) {
                return "error";
            }
            log.info("[{}:{}]开始执行业务", applicationName, serverPort);
            // 模拟业务内容
            TimeUnit.SECONDS.sleep(10);
            log.info("[{}:{}]执行业务中", applicationName, serverPort);
            TimeUnit.SECONDS.sleep(5);
            log.info("[{}:{}]执行业务中", applicationName, serverPort);
            TimeUnit.SECONDS.sleep(5);
            log.info("[{}:{}]业务执行完毕", applicationName, serverPort);
            return "success";
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        } finally {
            // 必须是当前持有锁的线程才能释放锁
            if (lock.isLocked() && lock.isHeldByCurrentThread()) {
                // 释放锁
                lock.unlock();
                log.info("[{}:{}]已经释放锁", applicationName, serverPort);
            }
        }
    }

    @GetMapping("/lockInMultiJvm")
    public String lockInMultiJvm() {

        return "success";
    }

    @PostConstruct
    private void init() {
        log.info("redisson单机实例 {}", redissonClient);
    }
}
